home *** CD-ROM | disk | FTP | other *** search
- /*
- * scan.c
- *
- * Scanner specific module of a scanner driver. This is a
- * template for developing a scanner driver for an SGI system;
- * add code that communicates with your scanner in the
- * appropriate places below, and link with main.o and libscan.a
- * to build a scanner driver.
- *
- * Copyright 1992, Silicon Graphics, Inc.
- * All Rights Reserved.
- *
- * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics, Inc.;
- * the contents of this file may not be disclosed to third parties, copied or
- * duplicated in any form, in whole or in part, without the prior written
- * permission of Silicon Graphics, Inc.
- *
- * RESTRICTED RIGHTS LEGEND:
- * Use, duplication or disclosure by the Government is subject to restrictions
- * as set forth in subdivision (c)(1)(ii) of the Rights in Technical Data
- * and Computer Software clause at DFARS 252.227-7013, and/or in similar or
- * successor clauses in the FAR, DOD or NASA FAR Supplement. Unpublished -
- * rights reserved under the Copyright Laws of the United States.
- */
-
- #ident "$Revision: 1.17 $"
-
- #include <sys/types.h>
- #include <sys/prctl.h>
-
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <dslib.h>
- #include <fcntl.h>
- #include <invent.h>
- #include <scanner.h>
- #include <scandrv.h>
-
- #include "scan.h"
- #include "main.h"
-
- /*
- * struct for the data from a SCSI inquiry command
- */
- typedef struct
- {
- unchar pqt:3; /* peripheral qual type */
- unchar pdt:5; /* peripheral device type */
- unchar rmb:1, /* removable media bit */
- dtq:7; /* device type qualifier */
- unchar iso:2, /* ISO version */
- ecma:3, /* ECMA version */
- ansi:3; /* ANSI version */
- unchar aenc:1, /* async event notification supported */
- trmiop:1, /* device supports 'terminate io process msg */
- res0:2, /* reserved */
- respfmt:3; /* SCSI 1, CCS, SCSI 2 inq data format */
- unchar ailen; /* additional inquiry length */
- unchar res1; /* reserved */
- unchar res2; /* reserved */
- unchar reladr:1, /* supports relative addressing (linked cmds) */
- wide32:1, /* supports 32 bit wide SCSI bus */
- wide16:1, /* supports 16 bit wide SCSI bus */
- synch:1, /* supports synch mode */
- link:1, /* supports linked commands */
- res3:1, /* reserved */
- cmdq:1, /* supports cmd queuing */
- softre:1; /* supports soft reset */
- unchar vid[8]; /* vendor ID */
- unchar pid[16]; /* product ID */
- unchar prl[4]; /* product revision level*/
- unchar vendsp[20];/* vendor specific; typically firmware info */
- unchar res4[40]; /* reserved for scsi 3, etc. */
- /* more vendor specific information may follow */
- } INQDATA;
-
- /*
- * SCANINFO *
- * OpenScanner(char *dev)
- *
- * Description:
- * Get a SCANINFO structure for the scanner connected to dev.
- * This opens the device and does an inquiry to find out what
- * kind of scanner is attached. If it's one we know about, we
- * allocate a SCANINFO structure, fill it in, and return it.
- *
- * Parameters:
- * dev device for the scanner
- *
- * Returns:
- * pointer to a SCANATTRIB if successful, NULL with drverr set if
- * error.
- */
-
- /*ARGSUSED*/
- SCANINFO *
- OpenScanner(char *dev)
- {
- static SCANINFO scan;
-
- /*
- * VERY IMPORTANT NOTE:
- *
- * If you are writing a driver for a SCSI scanner, and you are
- * using libds, make sure that you pass the O_EXCL flag defined in
- * /usr/include/fcntl.h to dsopen:
- *
- * dsreq_t *dsp = dsopen(dev, O_RDONLY | O_EXCL);
- *
- * If you pass the O_EXCL flag, the open will fail with errno set
- * to EBUSY if dev is the /dev/scsi device of a mounted disk;
- * otherwise, the open can succeed and you could really screw up
- * the disk!
- *
- * In addition, it is recommended that before issuing any other
- * SCSI commands you perform an inquiry command, and verify that
- * the device is a scanner by examining the Device Type code of
- * the inquiry buffer (this field should be set to 6. You can use
- * the INV_SCANNER #define from /usr/include/invent.h). It is
- * also recommended that you examine the vendor and product
- * identifiers to make sure the device is a scanner of the type
- * for which this driver is being written.
- */
-
- /*
- * Set the fields of scan to meaningful values as follows:
- *
- * scan.metric - Use this to indicate whether measurements are
- * in inches or centimeters. This applies to all the
- * fields of scan that we set that are measurements, and
- * when SetupScan is called (see below), this will be the
- * unit of measure for the scanning window and the
- * scanning resolution.
- *
- * scan.pagex, scan.pagey, scan.pagewidth, scan.pageheight - the
- * size of the scannable area supported by the scanner. Set
- * scan.pagex and pagey to the minimum horizontal and vertical
- * values for a scanning window (almost always 0 and 0), and
- * scan.pagewidth and scan.pageheight to the width and height
- * of the scanning area. The right edge of a scanning window
- * will not exceed scan.pagex + scan.pagewidth, and the bottom
- * edge will not exceed scan.pagey + scan.pageheight.
- *
- * scan.minxres, scan.maxxres, scan.minyres, scan.maxyres - Set
- * these to the minimum and maximum supported resolutions in
- * the horizontal and vertical directions.
- *
- * scan.xres, scan.yres - set these to arrays of floating point
- * numbers representing the discrete resolutions supported in
- * the horizontal and vertical directions respectively. If
- * the scanner we're supports arbitrary resolutions within the
- * ranges specified with scan.minxres, scan.maxxres,
- * scan.minyres, and scan.maxyres, we don't set these and we
- * set scan.nres to 0 (see below).
- *
- * scan.nres - Set this to the number of elements in scan.xres and
- * scan.yres (the arrays must have equal numbers of elements).
- * Set scan.nres to 0 to indicate that any resolution is
- * supported within the bounds indicated (see above).
- *
- * scan.types - Set this to point to an array of SCDATATYPE
- * structures, one for each of the data types this scanner
- * supports. See the Scanner API Specification for type
- * conventions for well-behaved scanner drivers.
- *
- * scan.ntypes - The number of types in the scan.types array.
- *
- * scan.options - An array of pointers to functions to implement
- * scanner specific options. Each function has the format of
- * the callback functions in main.c. Command values start at
- * SCN_SCANSPECIFIC (#defined in <scanipc.h>. The 0th element
- * of scan.types will be called when the command
- * (SCN_SCANSPECIFIC + 0) is received by the library, the 1st
- * element is called when the command (SCN_SCANSPECIFIC + 1)
- * is received, and so on. The interpretation of the SCARGS
- * and SCRES parameters should be agreed upon by this module
- * and the scanner specific option program that made the call.
- *
- * scan.noptions - The number of scanner specific options in
- * scan.options
- *
- * scan.priv - This is a private member for use of this module.
- * Set it to point to anything you want; this is useful for
- * avoiding the use of global variables within this module.
- */
-
- return &scan;
- }
-
- /*
- * int
- * SetupScan(SCANPARAMS *params)
- *
- * Description:
- * Get ready to perform a scan. params is a value result
- * parameter; it has fields that describe the scanning parameters
- * desired by the scanning application, and fields that this
- * function is responsible for setting.
- *
- * Parameters:
- * params scanning parameters (in/out)
- *
- * Returns:
- * 0 if successful, -1 with drverr set if error
- */
-
- /*ARGSUSED*/
- int
- SetupScan(SCANPARAMS *params)
- {
- /*
- * The input parameters to use to set up the scan are:
- * params->s - The SCANINFO struct we returned from OpenScanner
- *
- * params->xres, params->yres - scanning resolution.
- * These will be resolutions that we returned via the
- * SCANINFO struct from OpenScanner.
- *
- * params->x, params->y, params->width, params->height - The
- * scanning window. This will be inside the window
- * defined by the pagex, pagey, pagewidth, and pageheight
- * fields of the SCANINFO struct we returned from OpenScanner.
- *
- * params->type - The data type to scan. This will be one of
- * the types we returned via the SCANINFO struct from
- * OpenScanner.
- *
- * params->preview - 1 if this is a preview, 0 if this is a
- * final scan.
- *
- * params->maxmem - The maximum amount of memory to use for
- * each chunk we scan; params->xbytes * params->readlines
- * (see output parameters, below) should not exceed this
- * value. This is advisory, not enforced; if for some
- * reason it is necessary to set readlines such that
- * maxmem is exceeded, the main module of the driver will
- * honor params->readlines rather than adhering to
- * params->maxmem.
- *
- * Output parameters that we must set before returning 0:
- * params->xpixels - The number of pixels in a scan line
- *
- * params->xbytes - The number of bytes in a scan line
- *
- * params->ylines - The number of scan lines in the scan
- *
- * params->readlines - The number of scan lines to read at a
- * time. This parameter becomes significant in DoScan(),
- * below. In DoScan(), we get buffers from a scan queue
- * into which we're supposed to put the scan data; each
- * buffer will be big enough to hold params->readlines
- * lines of data.
- *
- * params->convert - Function to convert scan data to
- * params->type. The scanner may not directly support the
- * four basic types, but we may be able to convert to one
- * of them; for example, some scanners return color data
- * in a banded format, where the red, blue, and green
- * values for each scan line are together. In this case,
- * we would set params->convert to SCBandRGB8ToPixelRGB8;
- * this is the function in the scan library for doing the
- * conversion we want.
- *
- * If the scanner returns data in precisely the format
- * we're returning to the scanning application, no
- * conversion is necessary, and we can leave
- * params->convert alone (it will have been initialized to
- * NULL to indicate that no conversion is necessary).
- *
- * Other parameters
- * scanq, sfreeq - These are the queues for scan buffers, used
- * in DoScan below. They are not significant in ScanSetup
- * and should be ignored here.
- */
- drverr = SCEDEV; /* Generic "device error" error code; see */
- /* <scanner.h> for more specific error codes */
- return -1;
- }
-
- /*
- * int
- * ScanReset(SCANINFO *scan)
- *
- * Description:
- * Reset the scanner to its ready state. This is called after a
- * scan has been aborted.
- *
- * Parameters:
- * scan Describes the scanner to reset
- *
- * Returns:
- * 0 if successful, -1 with drverr set if error
- */
-
- /*ARGSUSED*/
- int
- ScanReset(SCANINFO *scan)
- {
- drverr = SCEDEV; /* Generic "device error" error code; see */
- /* <scanner.h> for more specific error codes */
- return -1;
- }
-
- /*
- * void
- * DoScan(SCANPARAMS *params)
- *
- * Description:
- * Perform a scan. We read the data from the scanner and put it on the
- * scan queue so that the image processing process can get it. This
- * function exits when it's done; it's called via sproc(2).
- *
- * Note: calls to SCEnqueue and SCDequeue may not return; that
- * is, these functions will call exit if our parent process sets
- * certain flags. Be careful that an exit from within SCEnqueue
- * or SCDequeue will not strand any memory or leave the address
- * space corrupted in any way.
- *
- * Parameters:
- * params parameters for the scan
- */
-
- void
- DoScan(SCANPARAMS *params)
- {
- void *buf;
- int toread, curline;
-
- (void)prctl(PR_TERMCHILD);
-
- for (curline = 0; curline < params->ylines;
- curline += params->readlines) {
- toread = MIN(params->readlines,
- params->ylines - curline);
-
- buf = SCDequeue(params->sfreeq); /* SCDequeue might exit! */
-
- /*
- * Get the scan data here!
- */
-
- /*
- * Chop the buffer up into scan line sized chunks
- */
- while (toread--) {
- SCEnqueue(params->scanq, buf); /* SCEnqueue might exit! */
- buf = (char *)buf + params->xbytes;
- }
- }
-
- exit(0);
- }
-
- /*
- * Document feeder functions.
- *
- * The template versions of these functions are simply stubs that
- * inform the application that no document feeder is attached to the
- * scanner. If you are writing a driver for a scanner that supports a
- * document feeder, these should be implemented appropriately.
- */
-
- /*
- * int
- * SetFeederFlags(SCANINFO *scan, SCFEEDERFLAGS flags)
- *
- * Description:
- * Set document feeder flags. flags should be set to either
- * SC_AUTOFEED or SC_PROGFEED, depending on whether the
- * application wants us to load the next document every time we
- * do a scan.
- *
- * This function should only get called if scan->feederFlags have
- * both the SC_AUTOFEED and SC_PROGFEED bits set, indicating that
- * the application has to choose how it wants the feeder to act.
- *
- * Parameters:
- * scan scanner info
- * flags either SC_AUTOFEED or SC_PROGFEED
- *
- * Returns:
- * 0 if successful, -1 if error
- */
-
- /*ARGSUSED*/
- int
- SetFeederFlags(SCANINFO *scan, SCFEEDERFLAGS flags)
- {
- drverr = SCENOFEEDER;
- return -1;
- }
-
- /*
- * int
- * AdvanceFeeder(SCANINFO *scan)
- *
- * Description:
- * Advance document feeder so that next document in the feeder
- * will be scanned from next time DoScan is called. This should
- * only be called if we support SC_PROGFEED. If we claimed
- * support for both SC_PROGFEED and SC_AUTOFEED, the application
- * should have called SetFeederFlags(SC_PROGFEED).
- *
- * Parameters:
- * scan scanner info.
- *
- * Returns:
- * 0 if successful, -1 if error
- */
-
- /*ARGSUSED*/
- int
- AdvanceFeeder(SCANINFO *scan)
- {
- drverr = SCENOFEEDER;
- return -1;
- }
-
- /*
- * int
- * FeederReady(SCANINFO *scan)
- *
- * Description:
- * Check whether the document feeder is ready; that is, it has
- * paper in it and will be used for scanning.
- *
- * Parameters:
- * scan scanner info
- *
- * Returns:
- * 0 if feeder is ready, -1 otherwise.
- */
-
- /*ARGSUSED*/
- int
- FeederReady(SCANINFO *scan)
- {
- drverr = SCENOFEEDER;
- return -1;
- }
-
- /*
- * The next two functions are used to implement the "-query" flag that
- * each scanner driver must support. scaninst uses this flag to get
- * information about scanners on the system and scanner drivers that
- * are installed to aid the user in setting up the
- * /var/scan/scanners file.
- */
-
- /*
- * void
- * PrintID(FILE *fp)
- *
- * Description:
- * Print a string to fp that describes the type of scanner that
- * this driver supports
- *
- * Parameters:
- * fp stream upon which to print scanner id string
- */
-
- void
- PrintID(FILE *fp)
- {
- (void)fprintf(fp, "Scanner Template\n"); /* String describing scanner */
- (void)fprintf(fp, "SCSI Serial Parallel\n");/* Device type; can be list */
- }
-
- /*
- * void
- * FindScanners(FILE *fp)
- *
- * Description:
- * Look for scanners that this driver can support. For each such
- * driver, print the type of device, a space, and then the file
- * to open to access that scanner (usually a device special
- * file).
- *
- * Type names are:
- * SCSI
- * Serial
- * Parallel
- * GPIB
- * EISA
- * Other
- *
- * Parameters:
- * fp stream upon which to print stuff
- */
-
- void
- FindScanners(FILE *fp)
- {
- inventory_t *inv;
- char device[100];
- dsreq_t *dsp;
- /* int because it must be word aligned. */
- int inqbuf[(sizeof(INQDATA) + 3)/sizeof(int)];
- INQDATA *inq = (INQDATA *)inqbuf;
-
- /*
- * This example looks for SCSI scanners; do whatever is necesary
- * to find other types of scanner here.
- */
- if (setinvent() < 0) {
- return;
- }
-
- while ((inv = getinvent()) != NULL) {
- if (inv->inv_class == INV_SCSI && inv->inv_type == INV_SCANNER) {
- (void)sprintf(device, "/dev/scsi/sc%dd%dl0", inv->inv_controller,
- inv->inv_unit);
- if ((dsp = dsopen(device, O_RDONLY)) == NULL) {
- continue;
- }
-
- if (inquiry12(dsp, (char *)inq, sizeof *inq, 0) == 0
- && strncmp((char *)inq->vid, "vendorXX", 8) == 0 &&
- strncmp((char *)inq->pid, "productXXXXXXXXX", 16) == 0) {
- (void)fprintf(fp, "SCSI %s\n", device);
- }
- dsclose(dsp);
- }
- }
-
- endinvent();
- }
-
- /*
- * int
- * InstallScanner(char *dev)
- *
- * Description:
- * This function gets called to implement the "-install" option
- * of the driver. The scanner installation tool wants to install
- * a scanner with us as the driver and dev as the device.
- *
- * This function should verify that this is a reasonable thing to
- * do, and should also take steps to ensure that all users can
- * access the scanner. This means that for SCSI scanners that
- * use the /dev/scsi interface, the following code should be
- * executed:
- *
- * chmod(dev, 0666);
- *
- * Suggestion: put the code that verfies that a device is valid
- * in the OpenScanner function, and then call OpenScanner from
- * within this function (InstallScanner). If OpenScanner returns
- * NULL, print an error message and return -1.
- *
- * If for any reason a scanner with us as the driver and dev as
- * the device should NOT be installed, print an error message to
- * stdout, and return -1. If it's OK to install the scanner,
- * return 0.
- *
- * If we print something and return -1, then scaninst will
- * display the string.
- *
- * Parameters:
- * dev Device to use to install scanner
- *
- * Returns:
- * 0 if successful, -1 if error.
- */
-
- int
- InstallScanner(char *dev)
- {
- (void)printf("The template driver doesn't support %s\n", dev);
- return -1;
- }
-
- /*
- * int
- * DeleteScanner(char *dev)
- *
- * Description:
- * This function gives the scanner driver the opportunity to
- * deallocate any resources allocated during InstallScanner, and
- * to do any scanner-specific cleanup necessary for deleting a
- * scanner.
- *
- * If an error occurs, print a message to stdout and return -1.
- * scaninst will display the message that gets printed and refuse
- * to delete the scanner.
- *
- * Parameters:
- * dev Device of scanner being deleted
- *
- * Returns:
- * 0 if successful, -1 if error.
- */
-
- /*ARGSUSED*/
- int
- DeleteScanner(char *dev)
- {
- return 0;
- }
-
- /*
- * void *
- * GetSaveOptions(SCANINFO *scan, int *nBytes)
- *
- * Description:
- * This function should return to the main.c module a pointer to
- * some bytes representing our current settings that we got from
- * our scanner specific options program. If we don't have a
- * scanner specific options program, we just set drverr and
- * return NULL.
- *
- * The reason for doing this is so that the scanner application
- * can save some state for us, and at a later time give us the
- * same bytes back so that we can make our state match what it
- * was before.
- *
- * Parameters:
- * scan SCANINFO
- * nBytes we fill this in with the number of bytes we're returning
- *
- * Returns:
- * pointer to bytes containing scanner specific options settings
- * if successful, NULL if error. drverr must be set to an
- * appropriate error code from <scanner.h> or <sys/errno.h> if an
- * error occurs.
- */
-
- void *
- GetSaveOptions(SCANINFO *scan, int *nBytes)
- {
- drverr = SCENOSAVEOPT;
- return NULL;
- }
-
- /*
- * int
- * SetSaveOptions(SCANINFO *scan, void *options, int nBytes)
- *
- * Description:
- * In this function, the scanner application is restoring state
- * that it previously saved after calling GetSaveOptions. We
- * should reset our state to reflect the options passed to us.
- *
- * These are scanner specific settings that were set by our
- * scanner specific options program; we don't need to worry about
- * things like resolution and scanning area and data type that
- * are a part of the standard scanning protocol here.
- *
- * Parameters:
- * scan SCANINFO
- * options the saved settings
- * nBytes number of bytes pointed to by options
- *
- * Returns:
- * 0 if successful, -1 if error. drverr must be set to an
- * appropriate error code from <scanner.h> or <sys/errno.h> if an
- * error occurs.
- */
-
- int
- SetSaveOptions(SCANINFO *scan, void *options, int nBytes)
- {
- drverr = SCENOSAVEOPT;
- return -1;
- }
-